compatible
這是一個字串型態的屬性,用途是把這個設備跟他的驅動程式綁定,像是 m_can 設備就會是 bosch家的驅動。
**compatible=** "manufacturer,model"
前面是製造商,後面是驅動檔案的名字
compatible= "bosch,m_can"
當然屬性不是只能放一個,也可以放好幾個值在一個屬性當中。
compatible= "bosch,m_can" , "bosch1,m_can1"
這樣寫的話當啟動時就會先以第一個值去找有沒有相同的驅動,沒有的話就會去查第二個驅動。
驅動程式的檔案當中都會有一個 OF Table , 在這個 Table 當中會存放一些 compatible ,如果我們寫的設備 compatible 與當中相同,就可以使用這個驅動。
static const struct of_device_id adnp_of_match[] = {
{ .compatible = "bosch,m_can", },
{ },
};
model
這個屬性也是個字串,通常用來說明開發板的名字or設備的訊息 EX:
model = "st,st32mp157";
status
用來說明這個設備室啟用或是禁用或是有問題
okay : 表示是可用或是啟動
disabled : 表示目前禁用,但未來可以隨時開啟,熱插拔功能
fail : 表示目前禁用,但未來可以隨時開啟
fail-sss : 表示目前禁用,但未來可以隨時開啟,但sss表示有錯誤
reg
reg 通常是 <address , length> , reg 屬性一般用於說明設備的地址或者其他的設備地址相關訊息,例如下方是
外圍的registers地址範圍。
reg = <0x4000e000 0x400>;
/* 這個設備的暫存器開頭地址是0x4000e000,地址長度範圍是0x400(通常該IC的手冊可以找到多大)*/
// 簡單來說就是開頭位置,然後範圍有多大。
#address-cells 和 #size-cells
這個屬性是 uint_32 的 type , 用在任何一個擁有子節點的設備當中,用來說明子節點的地址資訊。
#address-cells
: 指定節點中地址的長度,以單位數量表示。例如,#address-cells = <1>;
表示節點中每個地址由1個單位(通常是32位元或64位元整數)構成。這表示在此節點的 reg
屬性中,地址值將以1個單位來表示。
如果設為 <1>
,表示地址由1個單位組成(例如,一個32位的整數)。如果設為 <2>
,則地址由2個單位組成(例如,兩個32位的整數,通常用於64位地址)。
#size-cells
: 指定節點中大小的長度,以單位數量表示。例如,#size-cells = <0>;
表示節點中沒有需要描述的大小數量,或者說此節點的 reg
屬性中沒有大小資訊。這通常用於那些不需要指定大小的節點。
如果設為 <0>
,表示該節點沒有大小訊息,通常是因為節點本身不需要描述內存大小。如果設為 <1>
,則大小由1個單位表示;如果設為 <2>
,則由2個單位表示,常見於需要描述較大內存區域的情況。
假設我們有一個節點的 reg
屬性定義如下:
reg = <0x1000 0x2000>;
如果 #address-cells = <1>;
和 #size-cells = <1>;
,表示:
0x1000
。 → 也就是說 0x1000 是一個 32bits 的地址0x2000
。 → 也就是說 0x2000 是一個 32bit 的型態cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu0: cpu@0 {
compatible = "arm,cortex-a7";
device_type = "cpu";
reg = <0>; /* address=0,因為#size-cells是0,没有length,等於只設定了起始位置,
沒設定長度 */
clocks = <&scmi0_clk CK_SCMI0_MPU>;
clock-names = "cpu";
operating-points-v2 = <&cpu0_opp_table>;
nvmem-cells = <&part_number_otp>;
nvmem-cell-names = "part_number";
#cooling-cells = <2>;
};
};
scmi_sram: sram@2ffff000 {
compatible = "mmio-sram";
reg = <0x2ffff000 0x1000>;
#address-cells = <1>; /* 表示下面的 0X2FFFF000 是一個 32 bit 的地址*/
#size-cells = <1>; /* 表示下面的 0x1000 是一個 32bit 的type*/
ranges = <0 0x2ffff000 0x1000>;
scmi0_shm: scmi_shm@0 {
reg = <0 0x80>; /* 起始地址是0x0,長度是0x80 */
};
scmi1_shm: scmi_shm@200 {
reg = <0x200 0x80>;
};
};
ranges
ranges 可以是空或找按照 <子匯流排地址,父匯流排地址>來寫,ranges 是一個 addr mapping table , 由子地址跟父地址還有地址空間所組成:
child-bus-address:子匯流排地址空間的實體地址,由父節點的#address-cells決定此實體地址所佔用的長度。
parent-bus-address:父匯流排地址空間的實體地址,同樣由父節點的#address-cells確定此實體地址所佔用的字長度
length:子地址空間的長度,由父節點的#size-cells確定此地址長度所佔用的字長度
如果ranges屬性值為空值,表示子地址空間和父地址空間完全相同,不需要轉換,例如:
soc
{
compatible = "simple-bus";
...
ranges; # 這邊沒設定
};
ranges = <0 0x10000000 0x100000> /*指定一個1024kb(0x100000)的地址範圍,子地址空間的物理起始地址為0,父地址空間的物理起始地址為0x10000000。*/
sram: sram@10000000 {
compatible = "mmio-sram";
reg = <0x0 0x60000>; /* 定义了sram设备寄存器的起始地址为0,寄存器长度0x60000*/
#address-cells = <1>;
#size-cells = <1>;
ranges = <0 0x10000000 0x60000>; /* 经过地址转换,sram设备可以从0x10000000开始进行读写操作,0x10000000 = 0x0+0x10000000
}; */
基本上不需要自己硬幹一個 device tree 出來,通常SoC廠商就會提供 .dts 檔案。在 yocto 當中可能會以patch 的形式,當你pull code 的時候一併打patch。大多時候我們都是用 Soc 廠商 的 .dts 檔案來開發。但我們還是需要知道語法跟邏輯是什麼,因為後續可能會很常使用到。
可以引用的有 .dtsi , .dts , .h
,這些檔案都是可以在設備樹當中引用的!
下方文件是 stm32mp157.dtsi ,當中只定義了 cpu , dsi,就沒有其他的,但可以看到第7行引用了 153.dtsi ,我們可以一路找發現最後引用到了 151.dtsi
在153當中呢我們看到了 cpu1:cpu@1 , 表示還有cpu 0 。
比對一下SPEC可以發現 確實還有另外一個core ,所以我們繼續往上層引用搜尋。
在151當中可以看到另外一個core就寫在這拉!因為大多是共用的,為了減少重複寫所以可以直接引用其他版本的!
其他的像是 clock timer 等等,也都可以在設備樹找到相關的設定。總之所有有關硬體的描述都會定義在設備樹當中。